#ifndef __LAYOUT_SHADER_CPP__
#define __LAYOUT_SHADER_CPP__
#include "layout.h"
#include <lampe/types.h>
#include <IShaderConstantSetCallBack.h>
#include <IMaterialRendererServices.h>
#include <IGPUProgrammingServices.h>
#include <irrString.h>
#include <lampe/StringUtils.h>
namespace lampe{
namespace video{

class CLayoutShaderCallback : public irr::video::IShaderConstantSetCallBack{
    public:
        CLayoutShaderCallback(){};

        //Основная функция, непосредственно выполняющая передачу переменных
        void OnSetConstants(irr::video::IMaterialRendererServices* services, irr::s32 userData){
            //Номера текстурных слоёв.
            int baseTexture = 0;
            int layer1Texture = 1;
            int layer2Texture = 2;
            int layer3Texture = 3;
            int layer4Texture = 4;
            int layer5Texture = 5;
            int mask123Texture = 6;
            int mask45Texture = 7;
            //Передаём адреса текстур в шейдер, указывая на имена переменных,
            //которые должны их получить.
            services->setPixelShaderConstant("baseMap",(float*)(&baseTexture),1);
            services->setPixelShaderConstant("layer1",(float*)(&layer1Texture),1);
            services->setPixelShaderConstant("layer2",(float*)(&layer2Texture),1);
            services->setPixelShaderConstant("layer3",(float*)(&layer3Texture),1);
            services->setPixelShaderConstant("layer4",(float*)(&layer4Texture),1);
            services->setPixelShaderConstant("layer5",(float*)(&layer5Texture),1);
            services->setPixelShaderConstant("mask123",(float*)(&mask123Texture),1);
            services->setPixelShaderConstant("mask45",(float*)(&mask45Texture),1);
        }
};

	/**
	 * Создаёт шейдер отрисовки по слоям. Для правильной работы необходимо задать объекту на который будет
	 * установлен шейдер назначить правельные текстуры.
	 *
	 * @code
	 * s32 shaderMaterialType = createLayoutShader(5);
	 * terrain->scaleTexture(1.0f, 20.0f);
	 * terrain->setMaterialType((E_MATERIAL_TYPE)shaderMaterialType);
	 * terrain->setMaterialTexture( 0, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/grass.jpg") );
	 * terrain->setMaterialTexture( 1, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/sand.jpg") );
	 * terrain->setMaterialTexture( 2, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/dirt.jpg") );
	 * terrain->setMaterialTexture( 3, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/stone.jpg") );
	 * terrain->setMaterialTexture( 4, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/lava.jpg") );
	 * terrain->setMaterialTexture( 5, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/water.jpg") );
	 * terrain->setMaterialTexture( 6, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/mask123.jpg") );
	 * terrain->setMaterialTexture( 7, driver->getTexture("/home/caffeine/workspace/game_test/Debug/data/ter/mask45.jpg") );
	 * @endcode
	 *
	 * @param layoutType тип слоёв. 1 означает порядок текстур (от 0) базовая, маска, красный;
	 * 2 базовая, маска, красный, зелёный; 3 базовая, маска, красный, зелёный, синий;
	 * 4 базовая, маска, красный, зелёный, синий, вторая маска, красный; 4 базовая, маска,
	 * красный, зелёный, синий, вторая маска, красный, зелёный
	 * @return номер шейдера
	 */
    lampe::s32 createLayoutShader(irr::video::IGPUProgrammingServices*gpu,lampe::u8 layoutType){
	    irr::io::path psFileName = "/home/caffeine/workspace/game_test/Debug/data/shader/frag.glsl"; //фрагментный (пиксельный) шейдер
		irr::io::path vsFileName = "/home/caffeine/workspace/game_test/Debug/data/shader/vert.glsl"; //вертексный (вершинный) шейдер

		String vp="varying vec2 Texcoord;\nvarying vec2 Texcoord1;\nvoid main( void ){\ngl_Position = ftransform();\nTexcoord=gl_MultiTexCoord0.xy;\nTexcoord1=gl_MultiTexCoord1.xy;\n}";

		String layout_variable="";
		for (irr::u32 i=1;i<=layoutType;i++)
            layout_variable+=String("uniform sampler2D layer")+lampe::str::fromU32(i)+";\n";

		String layout_variable_fun="";
		for (irr::u32 i=1;i<=layoutType;i++)
            layout_variable_fun+=String("vec4 layer")+lampe::str::fromU32(i)+String("C = texture2D( layer")+lampe::str::fromU32(i)+", Texcoord1 );\n";

		String color1="";

		if (layoutType==1)
			color1="col = (layer1C-base)* mask1.r;\n";
		if (layoutType==2)
			color1="col = (layer1C-base)* mask1.r + (layer2C-base)* mask1.g;\n";
		if (layoutType>=3)
			color1="col = (layer1C-base)* mask1.r + (layer2C-base)* mask1.g + (layer3C-base)* mask1.b;\n";

		String color2="";
		if (layoutType==4)
			color2="col+=(layer4C-base)*mask2.r\n";
		if (layoutType==5)
			color2="col+=(layer4C-base)*mask2.r+(layer5C-base)*mask2.g;\n";

		String mask2="";
		String mask2_variable="";
		if (layoutType>=4){
			mask2="uniform sampler2D mask45;\n";
			mask2_variable="vec4 mask2 = texture2D (mask45, Texcoord );\n";
		}



		String fp=layout_variable+"uniform sampler2D baseMap;\n\
uniform sampler2D mask123;\n";
fp+=mask2+"\n\
varying vec2 Texcoord;\n\
varying vec2 Texcoord1;\n\
\n\
void main( void )\n\
{\n\
   vec4 base = texture2D( baseMap, Texcoord );\n\
   vec4 mask1 = texture2D (mask123, Texcoord );\n";
fp+=mask2_variable+"vec4 col;\n";

fp+=layout_variable_fun;
fp+=color1;
fp+=color2+"\
   base = base + col;\n\
   gl_FragColor = base;\n\
}";
		CLayoutShaderCallback* sC = new CLayoutShaderCallback();
		return gpu->addHighLevelShaderMaterial(vp.c_str(), "vertexMain", irr::video::EVST_VS_1_1,fp.c_str(), "pixelMain", irr::video::EPST_PS_1_1,sC,irr::video::EMT_SOLID);
	}

}//namespace video
}//namespace lampe
#endif
